package com.ideaaedi.springcloud.jd.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Sets;
import com.ideaaedi.springcloud.jd.commonds.entity.BaseCodeMsgEnum;
import com.ideaaedi.springcloud.jd.commonds.entity.PageInfo;
import com.ideaaedi.springcloud.jd.commonds.event.user.SysRoleDeletedEvent;
import com.ideaaedi.springcloud.jd.commonds.entity.user.po.SysRolePO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.po.SysUserRoleRePO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.req.SysRoleAddReqVO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.req.SysRoleListReqVO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.req.SysRoleUpdateReqVO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.resp.SysRoleDetailRespVO;
import com.ideaaedi.springcloud.jd.commonds.entity.user.vo.resp.SysRoleListRespVO;
import com.ideaaedi.springcloud.jd.commonds.exception.BaseException;
import com.ideaaedi.springcloud.jd.commonspring.mybatisplus.ServiceImplExt;
import com.ideaaedi.springcloud.jd.commonspring.util.JdContextUtil;
import com.ideaaedi.springcloud.jd.commonspring.validator.ValidId;
import com.ideaaedi.springcloud.jd.commonspring.validator.ValidTenant;
import com.ideaaedi.springcloud.jd.user.mapper.SysRoleMapper;
import com.ideaaedi.springcloud.jd.user.service.SysRoleService;
import com.ideaaedi.springcloud.jd.user.service.SysTenantService;
import com.ideaaedi.springcloud.jd.user.service.SysUserRoleReService;
import com.ideaaedi.springcloud.jd.user.support.UserCheckSupport;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统-角色表 服务实现类
 * </p>
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.1.A
 */
@Service
public class SysRoleServiceImpl extends ServiceImplExt<SysRoleMapper, SysRolePO> implements SysRoleService {
    
    @Resource
    private SysUserRoleReService sysUserRoleReService;
    
    @Resource
    private SysTenantService sysTenantService;
    
    @Resource
    private UserCheckSupport userCheckSupport;
    
    @Override
    public PageInfo<SysRoleListRespVO> list(SysRoleListReqVO req) {
        Integer type = req.getType();
        Integer state = req.getState();
        String code = req.getCode();
        String name = req.getName();
        String tenant = req.getTenant();
        IPage<SysRolePO> pageInfo = new Page<>(req.getPageNum(), req.getPageSize());
        IPage<SysRolePO> page = this.page(pageInfo, new LambdaQueryWrapper<SysRolePO>()
                .eq(type != null, SysRolePO::getType, type)
                .eq(state != null, SysRolePO::getState, state)
                .like(StringUtils.isNotBlank(code), SysRolePO::getCode, code)
                .likeRight(StringUtils.isNotBlank(tenant), SysRolePO::getTenant, tenant)
                .like(StringUtils.isNotBlank(name), SysRolePO::getName, name)
                .last("ORDER BY IFNULL(sort, " + Integer.MAX_VALUE + ") ASC, id DESC")
        );
    
        // 查询租户信息
        List<SysRolePO> records = page.getRecords();
        Set<String> tenantSet = records.stream()
                .filter(Objects::nonNull)
                .map(SysRolePO::getTenant).collect(Collectors.toSet());
        Map<String, String> tenantAndNameMap = sysTenantService.mappingTenantName(tenantSet, true);
    
        // 组装数据
        List<SysRoleListRespVO> list = records.stream().map(po -> {
            SysRoleListRespVO resp = new SysRoleListRespVO();
            BeanUtils.copyProperties(po, resp);
            resp.setTenantName(tenantAndNameMap.get(resp.getTenant()));
            return resp;
        }).collect(Collectors.toList());
        return PageInfo.of(page.getTotal(), req.getPageNum(), req.getPageSize(), list);
    }
    
    @Override
    public SysRoleDetailRespVO detail(Long roleId) {
        Objects.requireNonNull(roleId, "roleId cannot be null.");
        SysRolePO po = getById(roleId);
        if (po == null) {
            return null;
        }
        return detail(po);
    }
    
    @Override
    @ValidTenant
    @Transactional(rollbackFor = Exception.class)
    public SysRoleDetailRespVO update(SysRoleUpdateReqVO req) {
        Integer type = req.getType();
        Integer state = req.getState();
        String code = req.getCode();
        String name = req.getName();
        String remark = req.getRemark();
        Long id = req.getId();
        String tenant = req.getTenant();
        // 原来的po
        SysRolePO dbRole = getById(id);
        if (dbRole == null) {
            throw new BaseException("role id -> " + id, BaseCodeMsgEnum.DATA_NON_EXIST_OR_NON_DATA_PERMISSION);
        }
        if (StringUtils.isBlank(tenant)) {
            tenant = dbRole.getTenant();
        }
        if (StringUtils.isBlank(code)) {
            code = dbRole.getCode();
        }
        userCheckSupport.checkExistSameRoleCode(tenant, code, id);
        SysRolePO po = getById(id);
        po.setTenant(tenant);
        po.setCode(code);
        po.setName(name);
        po.setRemark(remark);
        po.setState(state);
        po.setType(type);
        updateById(po);
        return detail(id);
    }
    
    @Override
    @ValidTenant
    @Transactional(rollbackFor = Exception.class)
    public SysRoleDetailRespVO add(SysRoleAddReqVO req) {
        Integer type = req.getType();
        String code = req.getCode();
        String name = req.getName();
        String remark = req.getRemark();
        String tenant = req.getTenant();
        if (StringUtils.isBlank(tenant)) {
            tenant = JdContextUtil.currUserTenantNonNull();
        }
        userCheckSupport.checkExistSameRoleCode(tenant, code, null);
        long id = IdWorker.getId();
        SysRolePO po = new SysRolePO();
        po.setId(id);
        po.setTenant(tenant);
        po.setCode(code);
        po.setType(type);
        po.setName(name);
        po.setRemark(remark);
        save(po);
        return detail(id);
    }
    

    
    @Override
    @ValidId
    @Transactional(rollbackFor = Exception.class)
    public SysRoleDetailRespVO delete(Long roleId) {
        long roleUsedCount = sysUserRoleReService.count(new LambdaQueryWrapper<SysUserRoleRePO>()
                .eq(SysUserRoleRePO::getRoleId, roleId)
        );
        if (roleUsedCount > 0) {
            throw new BaseException(BaseCodeMsgEnum.ROLE_IS_USING);
        }
        SysRolePO po = getById(roleId);
        SysRoleDetailRespVO resp = detail(po);
        // 删除
        removeById(roleId);
        // 发布事件
        applicationContext.publishEvent(new SysRoleDeletedEvent(po));
        return resp;
    }
    
    @NonNull
    @Override
    public Set<Long> loadCurrUserRoleIds(@NonNull Long userId) {
        Objects.requireNonNull(userId, "userId cannot be null.");
        Set<Long> roleIdSet = sysUserRoleReService.list(new LambdaQueryWrapper<SysUserRoleRePO>()
                .eq(SysUserRoleRePO::getUserId, userId)
        ).stream().map(SysUserRoleRePO::getRoleId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(roleIdSet)) {
            return new HashSet<>();
        }
        final List<SysRolePO> roles = listByIds(roleIdSet);
        if (CollectionUtils.isEmpty(roles)) {
            return new HashSet<>();
        }
        return roles.stream().map(SysRolePO::getId).collect(Collectors.toSet());
    }
    
    @NotNull
    private SysRoleDetailRespVO detail(SysRolePO po) {
        final SysRoleDetailRespVO resp = new SysRoleDetailRespVO();
        BeanUtils.copyProperties(po, resp);
        String tenant = po.getTenant();
        if (StringUtils.isNotBlank(tenant)) {
            Map<String, String> tenantAndNameMap = sysTenantService.mappingTenantName(Sets.newHashSet(tenant), true);
            resp.setTenantName(tenantAndNameMap.get(tenant));
        }
        return resp;
    }
}
